#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;

#include <fcntl.h>
#include <getopt.h>

int readChunk(unsigned char buffer[][16], int buff_size, int device_fd) {
	int retval = read(device_fd, buffer, sizeof(char[buff_size][16]));
	if(retval == -1) {
		perror("Error while reading");
		return -1;
	}

	return (retval / sizeof(char[16]));
}

int writeChunk(unsigned char buffer[][16], int buff_size, FILE *output) {
	int retval;

	for(int i = 0; i < buff_size; ++buff_size) {
		for(int j = 0; j < 15; ++j) {
			retval = fprintf(output, "%i, ", buffer[i][j]);
			if(retval < 0) {
				perror("Error while writing");
				return 1;
			}
		}

		retval = fprintf(output, "%i\n", buffer[i][15]);
		if(retval < 0) {
			perror("Error while writing");
			return 1;
		}
	}

	return 0;
}

int process(int max_buff_size, int input_fd, FILE *output) {
	int retval = 42;
	unsigned char buffer[max_buff_size][16];

	while(retval > 0) {
		retval = readChunk(buffer, max_buff_size, input_fd);
		if(retval == -1)
			return -1;

		retval = writeChunk(buffer, retval, output);
		if(retval != 0)
			return -1;
	}

	return 0;
}

static struct option long_options[] = {
	{"input",	required_argument, 0, 'i'},
	{"output",	required_argument, 0, 'o'},
	{"buffer_size",	required_argument, 0, 'b'},
	{0, 0, 0, 0}
};

int main(int argc, char **argv) {
	int c;
	int option_index = 0;
	int size;
	int input_fd;
	FILE *output;
	char *input_filename = NULL;
	char *output_filename = NULL;
	int max_buff_size = 1 << 21;

	// Parse Arguements
	while(true) {
		c = getopt_long(argc, argv, "i:o:b:", long_options, 
				&option_index);
		if(c == -1)
			break;

		switch(c) {
			case 'i':
				size = sizeof(char[strlen(optarg)]);
				
				input_filename = (char *)malloc(size);
				if(input_filename == NULL) {
					perror("Error while mallocing");
					return 1;
				}

				strcpy(input_filename, optarg);
				break;
			case 'o':
				size = sizeof(char[strlen(optarg) + 1]);
				
				output_filename = (char *)malloc(size);
				if(output_filename == NULL) {
					perror("Error while mallocing");
					return 1;
				}

				strcpy(output_filename, optarg);
				break;
			case 'b':
				max_buff_size = atoi(optarg);
				break;
		}
	}
	
	// Sanity check options
	if(input_filename == NULL) {
		fprintf(stderr, "Error - no input given\n");
		return 1;
	}

	if(output_filename == NULL) {
		size = sizeof(char[strlen(input_filename) + 5]);

		output_filename = (char *)malloc(size);
		if(output_filename == NULL) {
			perror("Error while mallocing");
			return 1;
		}

		sprintf(output_filename, "%s.csv", input_filename);
	}

	// Open Files
	input_fd = open(input_filename, O_RDONLY, 
			S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
	if(input_fd == -1) {
		perror("Error opening input");
		return 1;
	}

	output = fopen(output_filename, "w");
	if(output == NULL) {
		perror("Error opening output");
		return 1;
	}
	
	// Run
	process(max_buff_size, input_fd, output);

	// Cleanup
	close(input_fd);
	fclose(output);
	free(input_filename);
	free(output_filename);
	
	return 0;
}
